import content_types
import random

class Room:
    """Class to describe a single room"""
    _top_left = None
    _bottom_right = None

    @property
    def top_left_corner(self):
        return self._top_left

    @property
    def bottom_right_corner(self):
        return self._bottom_right

    def __init__(self, top_left, bottom_right):
        """Instantiate room using two tuples for top left corner and bottom right corner"""
        self._top_left = top_left
        self._bottom_right = bottom_right

    def is_point_inside_room(self, x, y, padding = 0):
        """
        Check to see if a point is inside a room.
        Optional argument 'padding' to add extra padding to the room check.
        Returns True if the point is inside bounds.
        """
        return (self._top_left[0] - padding <= x <= self._bottom_right[0] + padding) and (self._top_left[1] - padding <= y <= self._bottom_right[1] + padding)


class Level:
    """Class to describe a single level."""
    _contentDict = dict()
    _rooms = list()
    
    def get_square_at(self,x,y):
        """Get the square type at the coordinates."""
        if (x,y) in self._contentDict.keys():
            return self._contentDict[(x,y)]
        else:
            return content_types.Void()

    def place_square_at(self, square, x, y):
        """Places content on the map at the coordinates."""
        self._contentDict[(x,y)] = square

    def create_empty_room(self, top_left_x, top_left_y, bottom_right_x, bottom_right_y):
        """
        Creates empty room by defining the top left coordinates, and the bottom right coordinates.
        """
        width = bottom_right_x - top_left_x + 1
        height = bottom_right_y - top_left_y + 1
        new_room = Room((top_left_x, top_left_y), (bottom_right_x, bottom_right_y))
        self._rooms.append(new_room)
        for y in range(0, height):
            for x in range(0, width):
                square = None
                if x == 0 or x == (width - 1) or y == 0 or y == (height - 1):
                    is_left = (x == 0)
                    is_right = (x == (width - 1))
                    is_top = (y == 0)
                    is_bottom = (y == (height - 1))                    
                    square = content_types.Wall(is_left, is_right, is_top, is_bottom)                                                                                                   
                else:
                    square = content_types.EmptyFloor()                
                self.place_square_at(square, top_left_x + x, top_left_y + y)
    
    def check_room_overlap(self, top_left_x, top_left_y, bottom_right_x, bottom_right_y):
        """
        Checks to see if a new room would overlap other rooms in the map. 
        Returns False when no overlap is detected
        Takes into consideration 1 square padding around existing rooms to allow for paths.
        """
        result = False        
        for room in self._rooms:            
            if room.is_point_inside_room(top_left_x, top_left_y, 1) or room.is_point_inside_room(bottom_right_x, bottom_right_y, 1):
                result = True
                break
        return result

    def generate_random_rooms(number_of_rooms, min_room_size=5, max_room_size=12, seed_x=0, seed_y=0):
        """
        Generates random rooms equal to number_of_rooms.
        Optional min_room_size and max_room_size to specify minimum and maximum height and width or rooms.
        Optional seed_x and seed_y to specify top left corner of first room.
        """
        random.seed()
        tl_x = seed_x
        tl_y = seed_y
        for n in range(0, number_of_rooms):
            size_x = random.randrange(min_room_size, max_room_size + 1)
            size_y = random.randrange(min_room_size, max_room_size + 1)
            br_x = tl_x + size_x
            br_y = tl_y + size_y

        
    def get_bounds(self):
        """
        Returns a tuple of two x,y tuples that define the upper left most coordinate and the bottom right most coordinate of the map.
        """        
        min_x = min(m[0] for m in self._contentDict.keys())
        max_x = max(m[0] for m in self._contentDict.keys())
        min_y = min(m[1] for m in self._contentDict.keys())
        max_y = max(m[1] for m in self._contentDict.keys())
        return ((min_x, min_y), (max_x, max_y))
        
    def __str__(self):
        bounds = self.get_bounds()
        text = ""
        for y in range(bounds[0][1], bounds[1][1] + 1):
            for x in range(bounds[0][0], bounds[1][0] + 1):
                text += str(self.get_square_at(x, y))
            text += "\n"
        return text

